import base64
import sys
import time
from datetime import datetime
import os
import traceback

import numpy as np
import requests
from cv2 import cv2
import subprocess
import logging

from colormath.color_objects import LabColor, sRGBColor
from colormath.color_conversions import convert_color
from colormath.color_diff import delta_e_cie2000

class Util:
    __Token = ''

    __TMP_IMAGE = './tmp/image.png'

    def __initToken(self):
        """ 初始化token """
        # 你的 APPID AK SK
        #APP_ID = '18540285'
        API_KEY = '4jBHa2k1I6BaqXObDXon8PM8'
        SECRET_KEY = '52OBvqTOSaSLYLPRI278Rabv5823zsjI'
        # client_id 为官网获取的AK， client_secret 为官网获取的SK
        host = 'https://aip.baidubce.com/oauth/2.0/token?grant_type=client_credentials&client_id=' + \
            API_KEY+'&client_secret='+SECRET_KEY
        response = requests.get(host)
        if response:
            self.__Token = response.json()['access_token']

    def __init__(self):
        if not os.path.exists('./tmp'):
            os.mkdir('./tmp')
        if not os.path.exists('./log'):
            os.mkdir('./log')
        self.__initToken()
        log_file = 'log/%s.log' % datetime.strftime(datetime.now(), '%Y-%m-%d')
        log_format = '%(message)s'
        logging.basicConfig(filename=log_file, level=logging.WARNING, format=log_format)
        self.__logger = logging.getLogger()

    def dayOfWeek(self):
        """ 今天星期几 """
        return datetime.now().isoweekday()

    __logger = ''
    def logOut(self, file, str):
        """ 日志输出 """
        logStr = time.strftime("%H:%M:%S", time.localtime()) + '|' + os.path.basename(file) + '|' + format(str)
        self.__logger.warning(logStr)
        print(logStr)

    def adb(self, command):
        """ 执行adb指令 
        
        :param command: adb的指令
        :returns: adb操作完成后的返回对象
        """
        AdbPath = '.\\bin\\adb_server.exe '
        ret = subprocess.run(AdbPath + command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, encoding="utf-8")
        if ret.returncode != 0:
            self.logOut(__file__,'adb subprocess error: {}'.format(command))
        return ret

    def getNumbers(self, size):
        """ 截图识数字 
        
        :param size: 需要截图的框框
        :returns: 识别出来的数字数组
        """
        # 图片先准备好
        img = self.grab(size)
        cv2.imwrite(self.__TMP_IMAGE, img)
        # 二进制方式打开图片文件
        f = open(self.__TMP_IMAGE, 'rb')
        img = base64.b64encode(f.read())

        limit = 3
        for l in range(limit):
            try:
                self.logOut(__file__,'getNumbers 识数字开始')
                request_url = 'https://aip.baidubce.com/rest/2.0/ocr/v1/numbers'
                params = {'image': img}
                access_token = self.__Token
                request_url = request_url + '?access_token=' + access_token
                headers = {'content-type': 'application/x-www-form-urlencoded'}
                response = requests.post(
                    request_url, data=params, headers=headers).json()
                list = []
                if 'error_code' in response:
                    self.logOut(__file__,"{}".format(response))
                    return list
                for i in range(response['words_result_num']):
                    list.append(response['words_result'][i]['words'])
                self.logOut(__file__,'getNumbers 识数字结束：{}'.format(list))
                return list
            except Exception as err:
                self.logOut(__file__,format(err))
                self.logOut(__file__,'==========')
                self.logOut(__file__,traceback.format_exc()) 
                continue
        return []

    def getWords(self, size):
        """ 截图识文字 
        
        :param size: 需要截图的框框
        :returns: 识别出来的文字数组
        """
        # 图片先准备好
        img = self.grab(size)
        cv2.imwrite(self.__TMP_IMAGE, img)
        # 二进制方式打开图片文件
        f = open(self.__TMP_IMAGE, 'rb')
        img = base64.b64encode(f.read())

        limit = 3
        for l in range(limit):
            try:
                self.logOut(__file__,'getWords 识字开始')
                request_url = 'https://aip.baidubce.com/rest/2.0/ocr/v1/general_basic'
                params = {'image': img}
                access_token = self.__Token
                request_url = request_url + '?access_token=' + access_token
                headers = {'content-type': 'application/x-www-form-urlencoded'}
                response = requests.post(
                    request_url, data=params, headers=headers).json()
                list = []
                if 'error_code' in response:
                    self.logOut(__file__,"{}".format(response))
                    return list
                for i in range(response['words_result_num']):
                    list.append(response['words_result'][i]['words'])
                self.logOut(__file__,'getWords 识字结束：{}'.format(list))
                return list
            except Exception as err:
                self.logOut(__file__,format(err))
                self.logOut(__file__,'==========')
                self.logOut(__file__,traceback.format_exc()) 
                continue
        return []
        
    def grab(self, size=(0, 0, 0, 0), flag=0, imageName='image'):
        """ 截图保存图片文件，返回cv2格式的图片
        
        :param size: 需要截图的框框                             默认(0, 0, 0, 0) - 全图截图
        :param flag: cv2读取图片的方式                          默认0 - 黑白图
        :param imageName: 截图保存的图片名字                    默认image
        :returns: cv2格式的截图
        """
        self.adb('shell screencap /storage/emulated/0/data/screen/{}.png'.format(imageName))
        self.adb('pull /storage/emulated/0/data/screen/{}.png .\\tmp'.format(imageName))
        if imageName != 'image':
            # 除了image 需要删掉源文件
            self.adb('shell rm -f /storage/emulated/0/data/screen/{}.png'.format(imageName))

        if size != (0, 0, 0, 0):
            return cv2.imread(self.__TMP_IMAGE, flag)[size[1]: size[3], size[0]: size[2]]
        else:
            return cv2.imread(self.__TMP_IMAGE, flag)

    def findPic(self, url, threshold=0.8, size=(0, 0, 0, 0), img=None, template=None):
        """ url图片与屏幕截图匹配
        
        :param url: 模板图片位置（带后缀）
        :param threshold: 匹配度 0~1的小数 数字越高越匹配        默认0.8
        :param size: 需要截图的框框                             默认(0, 0, 0, 0) - 全图截图
        :param img: cv2格式的截图                               默认None - 根据size进行截图
        :param template: cv2格式的模板图片                      默认None - 根据url读取模板图片
        :returns: 中心点x, y                                    (-1, -1) - 没找到
        """
        if np.all(img == None):
            img = self.grab(size) if size != (0, 0, 0, 0) else self.grab()
        if np.all(template == None):
            template = cv2.imread(url, 0)
        w, h = template.shape[::-1]
        res = cv2.matchTemplate(img, template, cv2.TM_CCOEFF_NORMED)
        min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res)
        cv2.waitKey(0)
        # self.logOut(__file__,"url: {}, threshold:{}, max_val: {}".format(url, threshold, max_val))
        if max_val >= threshold:
            return (max_loc[0] + w // 2, max_loc[1] + h // 2)
        else:
            return (-1, -1)

    def cmpColor(self, x, y, rgb, threshold=2.0):
        """ rgb与坐标的颜色是否匹配
        
        :param x, y: 坐标位置
        :param rgb: 元祖、数组格式的rgb
        :param threshold: 匹配度 数字越低越匹配                 默认2.0
        :returns: 是否匹配True/False
        """
        img = self.grab(flag=1)
        # self.showCv2Img(img)
        b, g, r = int(img[y, x][0]), int(img[y, x][1]), int(img[y, x][2])
        rgb2 = [r,g,b]

        # self.logOut(__file__,"rgb1 {}".format(rgb))
        # self.logOut(__file__,"rgb2 {}".format(rgb2))

        srgb1 = sRGBColor(*rgb, is_upscaled=True)
        lab1 = convert_color(srgb1, LabColor, target_illuminant='d50')
        # self.logOut(__file__,"lab1 {}".format(lab1.get_value_tuple()))

        srgb2 = sRGBColor(*rgb2, is_upscaled=True)
        lab2 = convert_color(srgb2, LabColor, target_illuminant='d50')
        # self.logOut(__file__,"lab2 {}".format(lab2.get_value_tuple()))

        delta_e = delta_e_cie2000(lab1, lab2)
        # self.logOut(__file__,"delta_e {}".format(delta_e))
        self.logOut(__file__,"cmpColor 识色 ({},{}) rgb1:{} rgb2:{} 匹配度：{}".format(x, y, rgb, rgb2, delta_e))
        return delta_e <= threshold

    def showCv2Img(self, img):
        """ 显示cv2图像 """
        self.logOut(__file__,"properties:shape:{},size:{},dtype:{}".format(img.shape,img.size,img.dtype))
        cv2.imshow('IMREAD_UNCHANGED+Gray', img)
        cv2.waitKey()

    def findPicLoop(self, url, threshold=0.8, size=(0, 0, 0, 0), timeSec = 600, img=None, template=None):
        """ 循环找图 直到找到退出

        :param url: 模板图片位置（带后缀）
        :param threshold: 匹配度 0~1的小数 数字越高越匹配        默认0.8
        :param size: 需要截图的框框                             默认(0, 0, 0, 0) - 全图截图
        :param timeSec: 等待时间（秒）                          默认600
        :param img: cv2格式的截图                               默认None - 根据size进行截图
        :param template: cv2格式的模板图片                      默认None - 根据url读取模板图片
        :returns: 中心点x, y                                    (-2, -2) - 没找到
        """
        self.logOut(__file__,'findPicLoop 循环找图开始 '+url)
        startTick = time.time()
        while True:
            if time.time() - startTick > timeSec:
                # 10分钟
                return (-2, -2)
            x, y = self.findPic(url, threshold, size, img, template)
            if x != -1 and y != -1:
                self.logOut(__file__,'findPicLoop 循环找图结束 ' + url)
                return (x, y)
        return (-2, -2)

    def findMulPicLoop(self, urlList, timeSec = 600):
        """ 循环找多图 直到找到退出

        :param urlList: 模板图片位置（带后缀）的数组
        :param timeSec: 等待时间（秒）                          默认600
        :returns: 中心点x, y, url                               (-2, -2, "") - 没找到
        """
        for url in urlList:
            self.logOut(__file__,'findMulPicLoop 循环找多图开始 ' + url)
        startTick = time.time()
        while True:
            if time.time() - startTick > timeSec:
                # 10分钟
                return (-2, -2, "")
            img = self.grab()
            for url in urlList:
                x, y = self.findPic(url, img = img)
                if x != -1 and y != -1:
                    self.logOut(__file__,'findMulPicLoop 循环找图结束 ' + url)
                    return (x, y, url)
        return (-2, -2, "")

    def notfindPicLoop(self, url, threshold=0.8, size=(0, 0, 0, 0)):
        """ 循环找多图 直到找不到退出

        :param url: 模板图片位置（带后缀）
        :param threshold: 匹配度 0~1的小数 数字越高越匹配        默认0.8
        :param size: 需要截图的框框                             默认(0, 0, 0, 0) - 全图截图
        """
        self.logOut(__file__,'notfindPicLoop 循环找没有图开始 ' + url)
        while True:
            x, y = self.findPic(url, threshold, size)
            if x == -1 and y == -1:
                self.logOut(__file__,'notfindPicLoop 循环找没有图结束 ' + url)
                return

    def isFindPic(self, url, threshold=0.8, size=(0, 0, 0, 0), img=None, template=None):
        """ 判断是否找到图

        :param url: 模板图片位置（带后缀）
        :param threshold: 匹配度 0~1的小数 数字越高越匹配        默认0.8
        :param size: 需要截图的框框                             默认(0, 0, 0, 0) - 全图截图
        :param img: cv2格式的截图                               默认None - 根据size进行截图
        :param template: cv2格式的模板图片                      默认None - 根据url读取模板图片
        :returns: 中心点x, y                                    (-1, -1) - 没找到
        """
        x, y = self.findPic(url, threshold, size, img, template)
        if x == -1 and y == -1:
            return False
        else:
            return True

    def exitScript(self):
        """ 退出脚本 """
        self.logOut(__file__,'脚本结束')
        sys.exit()

    def click(self, x, y):
        """ 点击

        :param x, y: 点击的坐标
        """
        self.logOut(__file__,'click ' + str(x) + ' ' + str(y))
        self.adb('shell input tap ' + str(x) + ' ' + str(y))

    def drag(self, x, y, x2, y2, ms = 300):
        """ 拖动

        :param x, y: 起始的坐标
        :param x2, y2: 结束的坐标
        :param ms: 拖动多少毫秒            默认300
        """
        self.logOut(__file__,'drag ' + str(x) + ' ' + str(y) + ' to ' + str(x2) + ' ' + str(y2))
        self.adb('shell input swipe ' + str(x) + ' ' + str(y) + ' ' + str(x2) + ' ' + str(y2) + ' ' + str(ms))

util = Util()
